package com.bosssoft.hr.train.j2se.util;

import com.bosssoft.hr.train.j2se.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.util.encoders.Hex;
/**
 * @Class UtilsDemo
 * @Description 对工具类的使用通过method 1 到 method7 进行了演示，通过作业能在后续
 * 开发中充分的利用系统提供的工具类不重复发明轮子，
 * 如果组织有对其封装则调用组织封装的这点依据实际的项目要求工作
 * @Author TangZaoBang
 * @Date 2023/04/27 17:11
 * @Version
 */
@Slf4j
public class UtilsDemo {


    /**
     * 直接将要排序的数组作为参数传入，经过方法以后数组已经排列完成，无需返回
     *  该方法为 sort
     * @param integerList 要排序的数组
     */
    public void method1(List<Integer> integerList ){
        /**
         * 通过例子我们了解集合类的sort方法，sort方法有诸多重载
         * 例如 Collections.sort(list,comparetor) 用于list内是对象需要依据对应的指定列比较
         * 的情况，这点和前面的作业TreeSet的排序输出相相似
         */
        Collections.sort(integerList);
        for (Integer integer : integerList) {
            log.info("元素"+ integer);
        }

    }

    /**
     * 首先在pom中引入 apache-common 下的 collection
     * Apache CollectionUtils
     * IsEmpty()该方法为集合判空
     * Exist（） ——matchesAny 它的作用是检查一个列表List中是否有任何元素与指定的字符串"python"（不区分大小写）相等。
     * AddAll()将另外一个lags2的数组并入本集合中，方便数组合并用词替代for循环合并数组
     * @param integerList 要操作的数组
     */
    public void method2( List<Integer> integerList){
        /**
         *    null 或者没有内容都返回false ，通过该方法可以实现优雅的空判断
         *    替代 if(null==interlist || integerList.size==0) then return true
         */
        log.info("判空测试结果："+ CollectionUtils.isEmpty(integerList));
        String[] lags = {"java", "python", "c"};
        //该方法接受两个参数：Iterable和Predicate。它将遍历Iterable中的所有元素，并对每个元素应用指定的Predicate。如果任何元素与Predicate匹配，则该方法返回true，否则返回false。
        // "python"::equalsIgnoreCase等价于lambda表达式(x -> "python".equalsIgnoreCase(x))，即比较传入的字符串是否与"python"相等（不区分大小写）。
        boolean b = IterableUtils.matchesAny(Arrays.asList(lags), "python"::equalsIgnoreCase);
        log.info("matchesAny测试结果"+b);
        //将另外一个lags2的数组并入本集合中，方便数组合并用词替代for循环合并数组
        String[] lags2 = {"java2", "python2", "c2"};
        List<String> list = new ArrayList<>(Arrays.asList(lags));
        CollectionUtils.addAll(list, lags2);
        log.info("AddAll()后lag列表结果：" + list);
    }

    /**
     * Arrays.asList（Integer[] ） 常用该方法把数组转化为列表List
     * @param score 要操作的数组
     */
    public void method3(Integer[] score){
        // 常用该方法把数组转化为列表
        List<Integer> scoreList=Arrays.asList(score);
        //数字排序 简单的支持 复杂的需要编写比较器 ,toArray 从列表转为数组
        Object[] scoreChange=scoreList.toArray();
        Arrays.sort(scoreChange);
        // 查找，使用二分查找加快速度
        Arrays.binarySearch(score,2);
        // 依次拷贝3个元素到数组
        Integer[] copyArray=Arrays.copyOf(score,3);
        log.info("copyArray"+Arrays.toString(copyArray));

    }

    /**
     *  FileUitl 封装了 文件的各种操作，包括目录操作，文件操作（文件删除，文件内容读取，文件写入等）
     *  下面例子演示了遍历某一个指定目录下的所有的文件，第2个代表类型，第3个参数代表递归遍历
     *  在项目开发中经常碰到文件操作因此有必要熟悉该工具类
     */
    public void method4(){
        Collection files= FileUtils.listFiles(new File("/"),new String[]{"*.java"},false);
        log.info(String.valueOf(files.isEmpty()));
    }

    /**
     * method5 字符串操作是项目中参见操作，建议使用字符串工具类操作
     * StringUtil ，该类在apache-common-lang3,
     * 该方法为 isEmpty  替代 string==null || string 内容为“”的判断
     */
    public void method5(){
        // 这个视为空
        StringUtils.isEmpty("");
        String hello="hello";
        //这个视图为空
        boolean empty = StringUtils.isEmpty(hello);
        log.info(String.valueOf(empty));
    }
    /**
     * method6对象拷贝是项目中参见操作例如 service层参数 DTO 转mapper操作的 entity，
     * 需要注意的是，Spring Framework中的BeanUtils.copyProperties()方法与Apache BeanUtils.copyProperties()方法不同，
     * 它不会调用目标对象的setter方法来设置属性值，而是直接访问目标对象的属性字段来设置属性值。这样可以避免一些潜在的安全漏洞，同时也提高了性能。
     * 该方法为 copyProperties  替代逐个的setXX方法
     */
    public void method6() throws InvocationTargetException, IllegalAccessException {
        User user=new User();
        user.setCode("BS0001");
        user.setName("同学1");
        /**
         * 如果对象列的太多没有使用copy则要单个赋值代码太繁琐，项目中多处用到对象拷贝
         *   注意 如果对象内部包含对象和链表数组则只是拷贝应用，需要引入手动完成拷贝
         *   对象拷贝库众多，效率上有所差别，如果对象数量比较大可以考虑其他的库，如果量不大
         *   apache BeanUtil.copy可以满足
         * */
        User userCopy=new User();
        BeanUtils.copyProperties(user,userCopy);
        log.info(String.valueOf(userCopy));

    }
    /**
     * method7对象拷贝是项目经常需要对用户输入的敏感数据加密例如 密码 等一些隐私数据，建议使用字符串工具类操作
     *  ，DigestUtils 替代 个人封装
     * 该方法为 copyProperties  替代逐个的setXX方法
     */
    public void method7() throws UnsupportedEncodingException {
        // MD5 加密  部分网站可以暴力破解
        String password="helloWorld";
        byte[] bytePassword=password.getBytes("utf-8");
        byte[] bytePasswordMD5 = DigestUtils.md5(bytePassword);
        log.info("MD5："+Arrays.toString(bytePasswordMD5));
    }

    /**
     *DigestUtils 替代 个人封装对用户输入的敏感数据加密例如 密码 等一些隐私数据，建议使用字符串工具类操作
     *
     */
    public void method8() {
        String password = "helloWorld";
        byte[] bytePassword = password.getBytes(StandardCharsets.UTF_8);
        SHAKEDigest digest = new SHAKEDigest(256);
        digest.update(bytePassword, 0, bytePassword.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        String hashString = Hex.toHexString(hash);
        log.info("SHA3-256:" + hashString);
    }






}
